package com.sooth.micro.camunda.service;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.dream.system.config.Page;
import com.sooth.common.core.domain.model.LoginUser;
import com.sooth.common.core.exception.ServiceException;
import com.sooth.common.json.utils.JsonUtils;
import com.sooth.common.satoken.utils.LoginHelper;
import com.sooth.micro.app.service.IMicroAppService;
import com.sooth.micro.app.view.MicroAppBo;
import com.sooth.micro.business.service.IMicroBusinessService;
import com.sooth.micro.business.view.SaveBo;
import com.sooth.micro.business.view.SaveColumnBo;
import com.sooth.micro.business.view.SaveResult;
import com.sooth.micro.business.view.SaveSubFormBo;
import com.sooth.micro.camunda.converter.BpmnBuilder;
import com.sooth.micro.camunda.converter.bean.BaseDefinition;
import com.sooth.micro.camunda.converter.bean.ProcessModel;
import com.sooth.micro.camunda.converter.bean.extension.ButtonPerm;
import com.sooth.micro.camunda.converter.bean.extension.ExtBpmConstant;
import com.sooth.micro.camunda.converter.bean.extension.FormPerm;
import com.sooth.micro.camunda.view.*;
import com.sooth.micro.field.service.IMicroFieldService;
import com.sooth.micro.field.view.MicroFieldBo;
import com.sooth.micro.page.service.IMicroPageService;
import com.sooth.micro.page.view.MicroPageBo;
import com.sooth.micro.process.service.IMicroProcessService;
import com.sooth.micro.process.view.MicroProcessBo;
import com.sooth.micro.process.view.MicroProcessVo;
import com.sooth.system.user.service.ISysUserService;
import com.sooth.system.user.view.SysUserVo;
import lombok.RequiredArgsConstructor;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricTaskInstance;
import org.camunda.bpm.engine.repository.Deployment;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.task.DelegationState;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.camunda.bpm.model.bpmn.instance.FlowElement;
import org.camunda.bpm.model.bpmn.instance.StartEvent;
import org.camunda.bpm.model.bpmn.instance.UserTask;
import org.camunda.bpm.model.bpmn.instance.camunda.CamundaProperty;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@RequiredArgsConstructor
@Service
public class MicroCamundaServiceImpl implements IMicroCamundaService {

    private final IMicroAppService appService;

    private final IMicroFieldService fieldService;

    private final IMicroPageService pageService;

    private final ICamundaApiService camundaApiService;

    private final IMicroProcessService processService;

    private final IMicroBusinessService businessService;

    private final ISysUserService userService;

    @Override
    public void deploy(DeployVo deployVo) {
        String processName = deployVo.getProcessName();
        MicroProcessBo processBo = processService.queryByAppId(deployVo.getAppId());
        if (processBo != null) {
            if (StrUtil.isEmpty(processName)) {
                processName = processBo.getProcessName();
            }
            camundaApiService.deploy(processBo.getProcessId(), processName, processBo.getProcessJson(), deployVo.getVersionTag());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void start(ProcessVo process) {
        String processDefinitionId = process.getProcessDefinitionId();
        ProcessDefinition processDefinition = camundaApiService.processDefinition(processDefinitionId);
        if (processDefinition == null) {
            throw new ServiceException("流程模型不存在");
        }
        MicroProcessBo processBo = processService.selectById(processDefinition.getKey());
        if (processBo == null) {
            throw new ServiceException("流程不存在");
        }
        Long appId = processBo.getAppId();
        List<SaveColumnBo> columns = process.getColumns();
        List<SaveSubFormBo> subForms = process.getSubForms();
        SaveBo saveBo = new SaveBo();
        saveBo.setAppId(appId);
        saveBo.setColumns(columns);
        saveBo.setSubForms(process.getSubForms());
        SaveResult saveResult = businessService.save(saveBo);
        Map<String, Object> formData = new HashMap<>(columns.size() + 1);
        for (SaveColumnBo microColumn : columns) {
            formData.put(microColumn.getColumn(), microColumn.getValue());
        }
        if (saveResult != null) {
            Object value = saveResult.getPrimVlue();
            formData.put(saveResult.getPrimColumn(), value);
        }
        if (CollUtil.isNotEmpty(subForms)) {
            for (SaveSubFormBo subForm : subForms) {
                Long entityId = subForm.getEntityId();
                List<SaveColumnBo> sinColumns = subForm.getSinColumns();
                List<List<SaveColumnBo>> mulColumns = subForm.getMulColumns();
                if (CollUtil.isNotEmpty(sinColumns)) {
                    Map<String, Object> joinTableMap = new HashMap<>(sinColumns.size());
                    for (SaveColumnBo microColumn : sinColumns) {
                        joinTableMap.put(microColumn.getColumn(), microColumn.getValue());
                    }
                    formData.put("$" + entityId, joinTableMap);
                } else if (CollUtil.isNotEmpty(mulColumns)) {
                    List<Map<String, Object>> columnList = new ArrayList<>(mulColumns.size());
                    for (List<SaveColumnBo> microColumnList : mulColumns) {
                        Map<String, Object> joinTableMap = new HashMap<>(sinColumns.size());
                        for (SaveColumnBo microColumn : microColumnList) {
                            joinTableMap.put(microColumn.getColumn(), microColumn.getValue());
                        }
                        columnList.add(joinTableMap);
                    }
                    formData.put("$" + entityId, columnList);
                }
            }
        }
        camundaApiService.start(processDefinitionId, formData);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approve(ApproveVo approveVo) {
        String taskId = approveVo.getTaskId();
        Task task = camundaApiService.task(taskId);
        String processDefinitionId = task.getProcessDefinitionId();
        ProcessDefinition processDefinition = camundaApiService.processDefinition(processDefinitionId);
        String processDefinitionKey = processDefinition.getKey();
        MicroProcessVo processVo = processService.query(processDefinitionKey);
        List<SaveColumnBo> columns = approveVo.getColumns();
        SaveBo saveBo = new SaveBo();
        saveBo.setPrimaryValue(approveVo.getPrimaryValue());
        saveBo.setAppId(processVo.getAppId());
        saveBo.setColumns(columns);
        saveBo.setSubForms(approveVo.getSubForms());
        SaveResult saveResult = businessService.save(saveBo);
        Map<String, Object> formData = new HashMap<>(columns.size() + 1);
        for (SaveColumnBo microColumn : columns) {
            formData.put(microColumn.getColumn(), microColumn.getValue());
        }
        if (saveResult != null) {
            Object value = saveResult.getPrimVlue();
            formData.put(saveResult.getPrimColumn(), value);
        }
        DelegationState delegationState = task.getDelegationState();
        if (DelegationState.PENDING.equals(delegationState)) {
            camundaApiService.resolveTask(taskId, formData);
        } else {
            camundaApiService.approve(taskId, formData, String.valueOf(LoginHelper.getUserId()));
        }
    }

    @Override
    public void reject(String taskId) {
        camundaApiService.reject(taskId);
    }

    @Override
    public ProcessModel convertToModelByProcessDefinitionId(String processDefinitionId) {
        ProcessDefinition processDefinition = camundaApiService.processDefinition(processDefinitionId);
        BpmnModelInstance bpmnModelInstance = camundaApiService.bpmnModelInstance(processDefinitionId);
        if (bpmnModelInstance != null && processDefinition != null) {
            BaseDefinition baseDefinition = BpmnBuilder.expose(bpmnModelInstance);
            ProcessModel processModel = new ProcessModel();
            processModel.setProcessId(processDefinition.getKey());
            processModel.setProcessName(processDefinition.getName());
            processModel.setProcessNode(baseDefinition);
            return processModel;
        }
        return null;
    }

    @Override
    public ProcessModel convertToModelByProcessInstanceId(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance = camundaApiService.historicProcessInstance(processInstanceId);
        String processDefinitionId = historicProcessInstance.getProcessDefinitionId();
        return convertToModelByProcessDefinitionId(processDefinitionId);
    }

    @Override
    public ProcessModel convertToModelByTaskId(String taskId) {
        Task task = camundaApiService.task(taskId);
        String processDefinitionId = task.getProcessDefinitionId();
        return convertToModelByProcessDefinitionId(processDefinitionId);
    }

    @Override
    public List<DeploymentVo> processDefinitionListByKey(String processDefinitionKey) {
        List<ProcessDefinition> processDefinitionList = camundaApiService.processDefinitionListByKey(processDefinitionKey);
        return deploymentVoList(processDefinitionList);
    }

    @Override
    public void suspendProcessDefinitionById(String processDefinitionId) {
        camundaApiService.suspendProcessDefinitionById(processDefinitionId);
    }

    @Override
    public void activateProcessDefinitionById(String processDefinitionId) {
        camundaApiService.activateProcessDefinitionById(processDefinitionId);
    }

    @Override
    public Page deploymentList(ProcessDefinitionDto processDefinitionDto, Page page) {
        Page<ProcessDefinition> processDefinitionPage = camundaApiService.processDefinitionList(processDefinitionDto, page);
        Collection<ProcessDefinition> rows = processDefinitionPage.getRows();
        List<DeploymentVo> deploymentVoList = deploymentVoList(rows);
        page.setRows(deploymentVoList);
        page.setTotal(processDefinitionPage.getTotal());
        return page;
    }

    private List<DeploymentVo> deploymentVoList(Collection<ProcessDefinition> rows) {
        List<DeploymentVo> deploymentVoList = null;
        if (CollUtil.isNotEmpty(rows)) {
            deploymentVoList = new ArrayList<>(rows.size());
            for (ProcessDefinition processDefinition : rows) {
                DeploymentVo deploymentVo = new DeploymentVo();
                String deploymentId = processDefinition.getDeploymentId();
                Deployment deployment = camundaApiService.deployment(deploymentId);
                deploymentVo.setDeploymentTime(deployment.getDeploymentTime());
                deploymentVo.setDeploymentId(deployment.getId());
                deploymentVo.setProcessName(deployment.getName());
                deploymentVo.setProcessDefinitionId(processDefinition.getId());
                deploymentVo.setProcessDefinitionKey(processDefinition.getKey());
                deploymentVo.setSuspended(processDefinition.isSuspended());
                deploymentVo.setVersion(processDefinition.getVersion());
                deploymentVo.setVersionTag(processDefinition.getVersionTag());
                deploymentVoList.add(deploymentVo);
            }
        }
        return deploymentVoList;
    }

    @Override
    public Page todoList(TodoTaskDto todoTaskDto, Page page) {
        Date[] endDates = todoTaskDto.getEndDate();
        Date startDate = null, endDate = null;
        if (endDates != null) {
            startDate = endDates[0];
            endDate = endDates[1];
        }
        LoginUser loginUser = LoginHelper.getLoginUser();
        Long userId = loginUser.getUserId();
        List<Long> deptIds = loginUser.getDeptIds();
        List<Long> roleIds = loginUser.getRoleIds();
        List<Long> postIds = loginUser.getPostIds();
        List<String> candidateList = new ArrayList<>(8);
        candidateList.add(String.valueOf(userId));
        if (CollUtil.isNotEmpty(deptIds)) {
            for (Long deptId : deptIds) {
                candidateList.add(String.valueOf(deptId));
            }
        }
        if (CollUtil.isNotEmpty(roleIds)) {
            for (Long roleId : roleIds) {
                candidateList.add(String.valueOf(roleId));
            }
        }
        if (CollUtil.isNotEmpty(postIds)) {
            for (Long postId : postIds) {
                candidateList.add(String.valueOf(postId));
            }
        }
        Page<Task> taskPage = camundaApiService.todoList(candidateList, todoTaskDto.getNodeName(), startDate, endDate, page);
        Collection<Task> rows = taskPage.getRows();
        List<TodoTaskVo> todoTaskVoList = null;
        if (CollUtil.isNotEmpty(rows)) {
            todoTaskVoList = new ArrayList<>(rows.size());
            for (Task task : rows) {
                TodoTaskVo todoTaskVo = new TodoTaskVo();
                String processInstanceId = task.getProcessInstanceId();
                HistoricProcessInstance historicProcessInstance = camundaApiService.historicProcessInstance(processInstanceId);
                if (historicProcessInstance != null) {
                    todoTaskVo.setStartDate(historicProcessInstance.getStartTime());
                    String startUserId = historicProcessInstance.getStartUserId();
                    SysUserVo userVo = user(startUserId);
                    if (userVo != null) {
                        todoTaskVo.setUserId(userVo.getId());
                        todoTaskVo.setNickName(userVo.getNickName());
                    }
                    String processDefinitionName = historicProcessInstance.getProcessDefinitionName();
                    todoTaskVo.setProcessName(processDefinitionName);
                }
                todoTaskVo.setTaskId(task.getId());
                todoTaskVo.setNodeName(task.getName());
                todoTaskVo.setEndDate(task.getCreateTime());
                todoTaskVoList.add(todoTaskVo);
            }
        }
        page.setRows(todoTaskVoList);
        page.setTotal(taskPage.getTotal());
        return page;
    }

    @Override
    public Page todoneList(TodoneTaskDto todoneTaskDto, Page page) {
        Date[] endDates = todoneTaskDto.getEndDate();
        Date startDate = null, endDate = null;
        if (endDates != null) {
            startDate = endDates[0];
            endDate = endDates[1];
        }
        Page<HistoricTaskInstance> taskInstancePage = camundaApiService.todoneList(String.valueOf(LoginHelper.getUserId()), todoneTaskDto.getNodeName(), startDate, endDate, page);
        Collection<HistoricTaskInstance> rows = taskInstancePage.getRows();
        List<TodoneTaskVo> todoneTaskVoList = null;
        if (CollUtil.isNotEmpty(rows)) {
            todoneTaskVoList = new ArrayList<>(rows.size());
            for (HistoricTaskInstance row : rows) {
                TodoneTaskVo todoneTaskVo = new TodoneTaskVo();
                String processInstanceId = row.getProcessInstanceId();
                HistoricProcessInstance historicProcessInstance = camundaApiService.historicProcessInstance(processInstanceId);
                Date startTime = row.getStartTime();
                Date endTime = row.getEndTime();
                if (historicProcessInstance != null) {
                    String startUserId = historicProcessInstance.getStartUserId();
                    if (StrUtil.isNotEmpty(startUserId)) {
                        Long userId = Long.valueOf(startUserId);
                        SysUserVo userVo = userService.queryNickName(userId);
                        if (userVo != null) {
                            todoneTaskVo.setUserId(userId);
                            todoneTaskVo.setNickName(userVo.getNickName());
                        }
                    }
                    String processDefinitionName = historicProcessInstance.getProcessDefinitionName();
                    todoneTaskVo.setProcessName(processDefinitionName);
                }
                todoneTaskVo.setProcessInstanceId(processInstanceId);
                todoneTaskVo.setStartDate(startTime);
                todoneTaskVo.setEndDate(endTime);
                todoneTaskVo.setNodeName(row.getName());
                todoneTaskVoList.add(todoneTaskVo);
            }
        }
        page.setRows(todoneTaskVoList);
        page.setTotal(taskInstancePage.getTotal());
        return page;
    }

    @Override
    public Page applyList(ApplyDto applyDto, Page page) {
        Date[] startDates = applyDto.getStartDate();
        Date startDate = null, endDate = null;
        if (startDates != null) {
            startDate = startDates[0];
            endDate = startDates[1];
        }
        Page<HistoricProcessInstance> historicProcessInstancePage = camundaApiService.applyList(String.valueOf(LoginHelper.getUserId()), applyDto.getProcessName(), startDate, endDate, page);
        Collection<HistoricProcessInstance> rows = historicProcessInstancePage.getRows();
        List<ApplyVo> applyVoList = null;
        if (CollUtil.isNotEmpty(rows)) {
            applyVoList = new ArrayList<>(rows.size());
            for (HistoricProcessInstance row : rows) {
                ApplyVo applyVo = new ApplyVo();
                String processInstanceId = row.getId();
                String processName = row.getProcessDefinitionName();
                Date startTime = row.getStartTime();
                Date endTime = row.getEndTime();
                String startUserId = row.getStartUserId();
                Long userId = Long.valueOf(startUserId);
                SysUserVo userVo = userService.queryNickName(userId);
                if (userVo != null) {
                    applyVo.setNickName(userVo.getNickName());
                }
                String processStatus = (String) camundaApiService.getVariable(processInstanceId, ExtBpmConstant.PROCESS_STATUS);
                applyVo.setProcessStatus(processStatus);
                applyVo.setProcessInstanceId(processInstanceId);
                applyVo.setProcessName(processName);
                applyVo.setStartDate(startTime);
                applyVo.setEndDate(endTime);
                applyVoList.add(applyVo);
            }
        }
        page.setRows(applyVoList);
        page.setTotal(historicProcessInstancePage.getTotal());
        return page;
    }

    @Override
    public ProcessModelVo getTaskModel(String taskId) {
        Task task = camundaApiService.task(taskId);
        String taskDefinitionKey = task.getTaskDefinitionKey();
        String processDefinitionId = task.getProcessDefinitionId();
        ProcessDefinition processDefinition = camundaApiService.processDefinition(processDefinitionId);
        FlowElement flowElement = camundaApiService.flowElement(processDefinition.getId(), taskDefinitionKey);
        UserTask userTask = (UserTask) flowElement;
        String processInstanceId = task.getProcessInstanceId();
        Map<String, Object> formData = camundaApiService.formData(processInstanceId);
        ProcessModelVo formModel = getProcessModel(userTask.getCamundaFormKey(), userTask, formData);
        return formModel;
    }

    @Override
    public ProcessModelVo getInstanceModel(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance = camundaApiService.historicProcessInstance(processInstanceId);
        String processDefinitionId = historicProcessInstance.getProcessDefinitionId();
        StartEvent startEvent = (StartEvent) camundaApiService.flowElement(processDefinitionId, null);
        if (startEvent != null) {

            Map<String, Object> formData = camundaApiService.formData(processInstanceId);
            ProcessModelVo processModel = getProcessModel(startEvent.getCamundaFormKey(), startEvent, formData);
            processModel.setButtonPermList(new ArrayList<>());
            Dict pageJson = processModel.getPageJson();
            Map formProps = (Map) pageJson.get("formProps");
            formProps.put("disabled", true);
            return processModel;
        }
        return null;
    }

    @Override
    public ProcessModelVo getProcessModel(String processDefinitionId) {
        StartEvent startEvent = (StartEvent) camundaApiService.flowElement(processDefinitionId, null);
        if (startEvent != null) {
            return getProcessModel(startEvent.getCamundaFormKey(), startEvent, null);
        }
        return null;
    }

    @Override
    public void deleteDeployment(String id) {
        camundaApiService.deleteDeployment(id);
    }

    @Override
    public List<HistoryRecordVo> listHistoryRecordByTaskId(String taskId) {
        Task task = camundaApiService.task(taskId);
        return listHistoryRecordByProcessInstanceId(task.getProcessInstanceId());
    }

    @Override
    public List<HistoryRecordVo> listHistoryRecordByProcessInstanceId(String id) {
        List<HistoricActivityInstance> historicActivityInstanceList = camundaApiService.historicActivityInstanceList(id);
        List<HistoryRecordVo> historyRecordVoList = new ArrayList<>(historicActivityInstanceList.size());
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) {
            String activityType = historicActivityInstance.getActivityType();
            if (!"exclusiveGateway".equals(activityType)) {
                String processInstanceId = historicActivityInstance.getProcessInstanceId();
                HistoricProcessInstance historicProcessInstance = camundaApiService.historicProcessInstance(processInstanceId);
                String startUserId = historicProcessInstance.getStartUserId();
                SysUserVo userVo = user(startUserId);
                String activityName = historicActivityInstance.getActivityName();
                Date startTime = historicActivityInstance.getStartTime();
                Date endTime = historicActivityInstance.getEndTime();
                Long duration = historicActivityInstance.getDurationInMillis();
                HistoryRecordVo historyRecordVo = new HistoryRecordVo();
                historyRecordVo.setProcessInstanceId(processInstanceId);
                historyRecordVo.setNodeName(activityName);
                historyRecordVo.setStartTime(startTime);
                historyRecordVo.setEndTime(endTime);
                historyRecordVo.setDuration(duration);
                historyRecordVo.setUserId(userVo.getId());
                historyRecordVo.setNickName(userVo.getNickName());
                historyRecordVoList.add(historyRecordVo);
            }
        }
        return historyRecordVoList;
    }

    @Override
    public void transfer(TransferVo transferVo) {
        String taskId = transferVo.getTaskId();
        Long userId = transferVo.getUserId();
        if (StrUtil.isEmpty(taskId)) {
            throw new ServiceException("转办任务不能为空");
        }
        if (userId == null) {
            throw new ServiceException("转办审批人不能为空");
        }
        camundaApiService.transfer(taskId, String.valueOf(userId));
    }

    @Override
    public void delegate(DelegateVo delegateVo) {
        String taskId = delegateVo.getTaskId();
        Long userId = delegateVo.getUserId();
        if (StrUtil.isEmpty(taskId)) {
            throw new ServiceException("委派任务不能为空");
        }
        if (userId == null) {
            throw new ServiceException("委派审批人不能为空");
        }
        camundaApiService.delegate(taskId, String.valueOf(userId));
    }

    private ProcessModelVo getProcessModel(String camundaFormKey, FlowElement flowElement, Map<String, Object> formData) {
        Long pageId = Long.valueOf(camundaFormKey);
        CamundaProperty camundaProperty = (CamundaProperty) flowElement.getExtensionElements().getElementsQuery().singleResult();
        List<FormPerm> formPermList = JsonUtils.parseArray(camundaProperty.getAttributeValue(ExtBpmConstant.FORM_PERM), FormPerm.class);
        List<ButtonPerm> buttonPermList = JsonUtils.parseArray(camundaProperty.getAttributeValue(ExtBpmConstant.BUTTON_PERM), ButtonPerm.class);
        MicroPageBo pageBo = pageService.selectById(pageId);
        ProcessModelVo processModelVo = new ProcessModelVo();
        if (MapUtil.isNotEmpty(formData)) {
            Long appId = pageBo.getAppId();
            MicroAppBo microApp = appService.selectById(appId);
            List<MicroFieldBo> pkFieldList = fieldService.selectPkByEntityId(microApp.getEntityId());
            if (CollUtil.isEmpty(pkFieldList) || pkFieldList.size() > 1) {
                throw new ServiceException("业务实体必须存在主键，且主键数量为1");
            }
            String primaryColumn = pkFieldList.get(0).getFieldCode();
            processModelVo.setPrimaryValue(formData.get(primaryColumn));
        }
        processModelVo.setNodeName(flowElement.getName());
        processModelVo.setButtonPermList(buttonPermList);
        Dict dict = JsonUtils.parseMap(pageBo.getPageJson());
        List<Map<String, Object>> widgetList = (List<Map<String, Object>>) dict.get("widgetList");
        editElProps(widgetList, formPermList, formData);
        processModelVo.setPageJson(dict);
        return processModelVo;
    }

    public void editElProps(List<Map<String, Object>> widgetList, List<FormPerm> formPermList, Map<String, Object> formData) {
        if (CollUtil.isNotEmpty(widgetList) && (CollUtil.isNotEmpty(formPermList) || MapUtil.isNotEmpty(formData))) {
            for (Map<String, Object> widget : widgetList) {
                String id = (String) widget.get("id");
                List<Map<String, Object>> subWidgetList = (List<Map<String, Object>>) widget.get("widgetList");
                if (CollUtil.isNotEmpty(formPermList)) {
                    for (FormPerm formPerm : formPermList) {
                        if (formPerm.getId().equals(id)) {
                            Map<String, Object> elPropsMap = (Map<String, Object>) widget.get("elProps");
                            if (formPerm.isReadonly()) {
                                elPropsMap.put("readonly", true);
                            }
                            if (formPerm.isHidden()) {
                                elPropsMap.put("hidden", true);
                            }
                            break;
                        }
                    }
                }
                if (MapUtil.isNotEmpty(formData)) {
                    if ("SubForm".equals(widget.get("type"))) {
                        Map<String, Object> propMap = (Map<String, Object>) widget.get("elProps");
                        Long entityId = (Long) propMap.get("entityId");
                        if (entityId != null) {
                            Object value = formData.get("$" + entityId);
                            if (value != null) {
                                if (value instanceof Map<?, ?>) {
                                    editElProps(subWidgetList, formPermList, (Map<String, Object>) value);
                                } else if (value instanceof List<?>) {
                                    for (Map<String, Object> subWidget : subWidgetList) {
                                        Map<String, Object> formItemProps = (Map<String, Object>) subWidget.get("formItemProps");
                                        if (formItemProps != null) {
                                            subWidget.put("id", formItemProps.get("prop"));
                                        }
                                    }
                                    List<Map<String, Object>> mapList = (List<Map<String, Object>>) value;
                                    widget.put("id", "$" + entityId);
                                    propMap.put("defaultValue", mapList);
                                }
                            }
                        }
                    } else {
                        Map<String, Object> formItemProps = (Map<String, Object>) widget.get("formItemProps");
                        if (formItemProps != null) {
                            String prop = (String) formItemProps.get("prop");
                            Object defaultValue = formData.get(prop);
                            if (defaultValue != null) {
                                Map<String, Object> propMap = (Map<String, Object>) widget.get("elProps");
                                propMap.put("defaultValue", defaultValue);
                            }
                        }
                        editElProps(subWidgetList, formPermList, formData);
                    }
                }
            }
        }
    }

    public SysUserVo user(String startUserId) {
        if (StrUtil.isNotEmpty(startUserId)) {
            Long userId = Long.valueOf(startUserId);
            SysUserVo userVo = userService.queryNickName(userId);
            userVo.setId(userId);
            return userVo;
        }
        return null;
    }
}
